home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ETO Development Tools 4
/
ETO Development Tools 4.iso
/
Tools - Objects
/
MacApp
/
MacApp 2.0.1
/
MacApp CD Release
/
MacApp 2.0.1 (Hard Disk Ready)
/
Libraries
/
UViewCoords.a
< prev
Wrap
Text File
|
1990-10-25
|
23KB
|
795 lines
;=============================================================================
; Copyright © 1988-1990 Apple Computer, Inc. All rights reserved.
; UViewCoords assembly language routines
Blanks On
String AsIs
Case On
Print Off
Include 'Macros.a'
LOAD 'ProgStrucMacs.d'
LOAD 'FlowCtlMacs.d'
Print On
case off
Seg 'MAUtilitiesRes'
kMaxCoord Equ 30000 ; Max coordinate for small views.
;---------------------------------------------
Macro
ResvLong
CASE on
If qDebug Then
Move.L #'rgrg',-(SP)
Else
Clr.L -(SP)
EndIf
CASE off
EndM
;---------------------------------------------
Macro
PopRts &amt
LclA &size
&size: SetA &Eval(&amt)
MoveA.L (SP)+,A0 ; A0 := return address
If &size > 8 Then
Lea &size(SP),SP
Else
AddQ.W #&size,SP
EndIf
Jmp (A0)
EndM
********************************************************************************************
* PROCEDURE PtToVPt (thePt: Point; VAR theVPt: VPoint);
* Converts the given Point to a VPoint.
*
* Trashes: D0,A0
********************************************************************************************
PtToVPt Proc Export
StackFrame Record 0,Increment
RetAddr Ds.L 1
theVPt Ds.L 1
thePt Ds.W 2
ArgSize Equ *-4
EndR
With StackFrame
MoveA.L theVPt(SP),A0 ; A0 := address of theVPt.
Move.W thePt(SP),D0 ; D0 := thePt.v.
Ext.L D0 ; Convert vertical coord to a long.
Move.L D0,(A0)+ ; Save it in theVPt.v.
Move.W thePt+2(SP),D0 ; D0 := thePt.h.
Ext.L D0 ; Convert horizontal coord to a long.
Move.L D0,(A0) ; Save it in theVPt.h.
PopRts ArgSize ; Pop arguments off stack and return
EndProc
********************************************************************************************
* FUNCTION VPtToPt (theVPt: VPoint): Point;
* Converts the given VPoint to a Point.
*
* Trashes: D0,D1,D2,A0
********************************************************************************************
VPtToPt Func Export
StackFrame Record 0,Increment
RetAddr Ds.L 1
theVPt Ds.L 1
ArgSize Equ *-4
RetValue Ds.W 2
EndR
With StackFrame
MoveA.L theVPt(SP),A0 ; A0 := address of theVPt.
Move.L #kMaxCoord,D1
Move.L D1,D2 ; Saves a couple bytes and is faster
Neg.L D2 ; D2 := -kMaxCoord
Move.L (A0)+,D0 ; Get vertical coord of theVPt
Cmp.L D1,D0 ; Is theVPt.v > kMaxCoord?
Bgt.S @1 ; Yes, branch.
Cmp.L D2,D0 ; No. Is theVPt.v < -kMaxCoord?
Bge.S @2 ; No, branch.
Move.L D2,D0 ; Set value to -kMaxCoord
Bra.S @2
@1
Move.L D1,D0 ; Set value to kMaxCoord
@2
Move.W D0,RetValue(SP) ; RetValue.v := D0.
Move.L (A0),D0 ; Get horizontal coord of theVPt.
Cmp.L D1,D0 ; Is theVPt.h > kMaxCoord?
Bgt.S @3 ; Yes, branch.
Cmp.L D2,D0 ; No. Is theVPt.h < -kMaxCoord?
Bge.S @4 ; No, branch.
Move.L D2,D0 ; Set value to -kMaxCoord.
Bra.S @4
@3
Move.L D1,D0 ; Set value to kMaxCoord.
@4
Move.W D0,RetValue+2(SP) ; RetValue.h := D0.
PopRts ArgSize ; Pop arguments off stack and return.
EndProc
********************************************************************************************
* PROCEDURE RectToVRect (theRect: Rect; VAR theVRect: VRect);
* Converts the given Rect to a VRect.
*
* Trashes: D0,A0,A1
********************************************************************************************
RectToVRect Proc Export
StackFrame Record 0,Increment
RetAddr Ds.L 1
theVRect Ds.L 1
theRect Ds.L 1
ArgSize Equ *-4
EndR
With StackFrame
MoveA.L theRect(SP),A0 ; Get address of theRect.
MoveA.L theVRect(SP),A1 ; Get address of theVRect.
Move.W (A0)+,D0 ; Copy top.
Ext.L D0
Move.L D0,(A1)+
Move.W (A0)+,D0 ; Copy left.
Ext.L D0
Move.L D0,(A1)+
Move.W (A0)+,D0 ; Copy bottom.
Ext.L D0
Move.L D0,(A1)+
Move.W (A0),D0 ; Copy right.
Ext.L D0
Move.L D0,(A1)
PopRts ArgSize ; Pop arguments off stack and return.
EndProc
********************************************************************************************
* PROCEDURE VRectToRect (theVRect: VRect; VAR theRect: Rect);
* Converts the given VRect to a Rect.
*
* Trashes: D0,D1,D2,A0,A1
********************************************************************************************
VRectToRect Proc Export
StackFrame Record 0,Increment
RetAddr Ds.L 1
theRect Ds.L 1
theVRect Ds.L 1
ArgSize Equ *-4
EndR
With StackFrame
MoveA.L theRect(SP),A1 ; Get address of theVRect.
; VPtToPt must not futz with A1!!!
ResvLong ; Space for result of VPtToPt.
Move.L theVRect+4(SP),-(SP); Push address of theVRect.topLeft.
Bsr VPtToPt ; Convert topLeft.
Move.L (SP)+,(A1)+ ; Save topLeft.
ResvLong ; Space for result of VPtToPt.
Move.L theVRect+4(SP),-(SP); Push address of theVRect.botRight.
AddQ.L #8,(SP)
Bsr VPtToPt ; Convert botRight.
Move.L (SP)+,(A1) ; Save botRight.
PopRts ArgSize ; Pop arguments off stack and return.
EndProc
********************************************************************************************
* PROCEDURE AddVPt (srcVPt: VPoint; VAR dstVPt: VPoint);
* Adds srcVPt to dstVPt, leaving result in dstVPt.
*
* Trashes: A0,A1,D0
********************************************************************************************
AddVPt Proc Export
StackFrame Record 0,Increment
RetAddr Ds.L 1
dstVPt Ds.L 1
srcVPt Ds.L 1
ArgSize Equ *-4
EndR
With StackFrame
MoveA.L srcVPt(SP),A0 ; Get addresses.
MoveA.L dstVPt(SP),A1
Move.L (A0)+,D0 ; Add vertical coordinate.
Add.L D0,(A1)+
Move.L (A0),D0 ; Add horizontal coordinate.
Add.L D0,(A1)
PopRts ArgSize ; Pop arguments off stack and return.
EndProc
********************************************************************************************
* PROCEDURE SubVPt (srcVPt: VPoint; VAR dstVPt: VPoint);
* Subtracts srcVPt from dstVPt, leaving result in dstVPt.
*
* Trashes: A0,A1,D0
********************************************************************************************
SubVPt Proc Export
StackFrame Record 0,Increment
RetAddr Ds.L 1
dstVPt Ds.L 1
srcVPt Ds.L 1
ArgSize Equ *-4
EndR
With StackFrame
MoveA.L srcVPt(SP),A0 ; Get addresses.
MoveA.L dstVPt(SP),A1
Move.L (A0)+,D0 ; Subtract vertical coordinate.
Sub.L D0,(A1)+
Move.L (A0),D0 ; Subtract horizontal coordinate.
Sub.L D0,(A1)
PopRts ArgSize ; Pop arguments off stack and return.
EndProc
********************************************************************************************
* PROCEDURE SetVPt (VAR vPt: VPoint; h, v: VCoordinate);
* Sets vPt to the given horizontal and vertical coordinates.
*
* Trashes: A0
********************************************************************************************
SetVPt Proc Export
StackFrame Record 0,Increment
RetAddr Ds.L 1
v Ds.L 1
h Ds.L 1
VPt Ds.L 1
ArgSize Equ *-4
EndR
With StackFrame
MoveA.L VPt(SP),A0 ; Get address of vPt.
Move.L v(SP),(A0)+ ; Copy vertical coordinate.
Move.L h(SP),(A0) ; Copy horizontal coordinate.
PopRts ArgSize ; Pop arguments off stack and return.
EndProc
********************************************************************************************
* FUNCTION EqualVPt (pt1, pt2: VPoint): BOOLEAN;
* Returns true if pt1 and pt2 are equal.
*
* Trashes: D0,A0,A1
********************************************************************************************
EqualVPt Func Export
StackFrame Record 0,Increment
RetAddr Ds.L 1
pt2 Ds.L 1
pt1 Ds.L 1
ArgSize Equ *-4
RetValue Ds.W 1
EndR
With StackFrame
MoveA.L pt1(SP),A0 ; Get address of pt1.
MoveA.L pt2(SP),A1 ; Get address of pt2.
CmpM.L (A0)+,(A1)+ ; Are vertical coordinates equal?
Bne.S @1 ; If they weren't equal, we're already done
CmpM.L (A0)+,(A1)+ ; Are horizontal coordinates equal?
@1: Seq D0 ; true if equal
Neg.B D0 ; Blaise wants false=0, true=1
Move.B D0,RetValue(SP) ; Set result
PopRts ArgSize ; Pop arguments off stack and return.
EndProc
********************************************************************************************
* PROCEDURE SetVRect (VAR r: VRect; left, top, right, bottom: VCoordinate);
* Sets r to the given coordinates.
*
* Trashes: A0
********************************************************************************************
SetVRect Proc Export
StackFrame Record 0,Increment
RetAddr Ds.L 1
bottom Ds.L 1
right Ds.L 1
top Ds.L 1
left Ds.L 1
r Ds.L 1
ArgSize Equ *-4
EndR
With StackFrame
MoveA.L r(SP),A0 ; Get address of r.
Move.L top(SP),(A0)+ ; Set the coordinates.
Move.L left(SP),(A0)+
Move.L bottom(SP),(A0)+
Move.L right(SP),(A0)
PopRts ArgSize ; Pop arguments off stack and return.
EndProc
********************************************************************************************
* PROCEDURE OffsetVRect (VAR r: VRect; dh, dv: VCoordinate);
* Offsets the coordinates of the given rectangle by dh and dv.
*
* Trashes: A0,D0,D1
********************************************************************************************
OffsetVRect Proc Export
StackFrame Record 0,Increment
RetAddr Ds.L 1
dv Ds.L 1
dh Ds.L 1
r Ds.L 1
ArgSize Equ *-4
EndR
With StackFrame
MoveA.L r(SP),A0 ; Get address of r.
Move.L dh(SP),D0 ; Get horizontal offset.
Move.L dv(SP),D1 ; Get vertical offset.
Add.L D1,(A0)+ ; Add vertical offset to top.
Add.L D0,(A0)+ ; Add horizontal offset to left.
Add.L D1,(A0)+ ; Add vertical offset to bottom.
Add.L D0,(A0) ; Add horizontal offset to right.
PopRts ArgSize ; Pop arguments off stack and return.
EndProc
********************************************************************************************
* PROCEDURE InsetVRect (VAR r: VRect; dh, dv: VCoordinate);
* Insets the given rectangle by dh and dv.
*
* Trashes: A0,A1,D0,D1
********************************************************************************************
InsetVRect Proc Export
Import ValidateRect
StackFrame Record 0,Increment
RetAddr Ds.L 1
dv Ds.L 1
dh Ds.L 1
r Ds.L 1
ArgSize Equ *-4
EndR
With StackFrame
MoveA.L r(SP),A0 ; Get address of r.
MoveA.L A0,A1
Move.L dh(SP),D0 ; Get horizontal offset.
Move.L dv(SP),D1 ; Get vertical offset.
Add.L D1,(A1)+ ; Add vertical offset to top.
Add.L D0,(A1)+ ; Add horizontal offset to left.
Sub.L D1,(A1)+ ; Subtract vertical offset to bottom.
Sub.L D0,(A1) ; Subtract horizontal offset to right.
Bsr ValidateRect
PopRts ArgSize ; Pop arguments off stack and return.
EndProc
********************************************************************************************
* PROCEDURE Pt2VRect (pt1, pt2: VPoint; VAR: dstRect: VRect);
* Set dstRect to the given top-left and bottom-right.
*
* Trashes: D0,D1,A0,A1
********************************************************************************************
Pt2VRect Proc Export
StackFrame Record 0,Increment
RetAddr Ds.L 1
dstRect Ds.L 1
pt2 Ds.L 1
pt1 Ds.L 1
ArgSize Equ *-4
EndR
With StackFrame
MoveA.L dstRect(SP),A0 ; Get address of dstRect into A0.
MoveA.L pt1(SP),A1 ; Get address of pt1 into A1.
MoveM.L (A1),D0/D1 ; Move topLeft
MoveM.L D0/D1,(A0)
MoveA.L pt2(SP),A1 ; Get address of pt2 into A1.
MoveM.L (A1),D0/D1 ; Move botRight
MoveM.L D0/D1,8(A0)
Lea 8(A0),A1 ; A1 := dstRect.botRight
; At this point, D0 = bottom, D1 = right
; A0 => dstRect.topLeft, A1 => dstRect.botRight
CmpM.L (A0)+,(A1)+ ; Is top > bottom?
Bge.S @1 ; No, skip swap
Move.L -4(A0),-4(A1) ; bottom := top
Move.L D0,-4(A0) ; top := bottom
@1: CmpM.L (A0)+,(A1)+ ; Is left > right?
Bge.S @2 ; No, okay to exit
Move.L -4(A0),-4(A1) ; right := left
Move.L D1,-4(A0) ; left := right
@2: PopRts ArgSize ; Pop arguments off stack & retu
EndProc
********************************************************************************************
* FUNCTION PtInVRect (pt: VPoint; r: VRect): BOOLEAN;
* Returns true if the given point lies within the given rectangle.
*
* Trashes: A0,A1,D0
********************************************************************************************
PtInVRect Func Export
StackFrame Record 0,Increment
RetAddr Ds.L 1
r Ds.L 1
pt Ds.L 1
ArgSize Equ *-4
RetValue Ds.W 1
EndR
With StackFrame
Clr.B RetValue(SP) ; Prime result to FALSE
MoveA.L pt(SP),A0 ; Get address of pt.
Move.L A0,D0 ; Save address
MoveA.L r(SP),A1 ; Get address of r.
CmpM.L (A0)+,(A1)+ ; If pt.v < r.top then fail.
Bgt.S @2
CmpM.L (A0)+,(A1)+ ; If pt.h < r.left then fail.
Bgt.S @2
MoveA.L D0,A0 ; Get address of pt, again.
CmpM.L (A0)+,(A1)+ ; If pt.v >= r.bottom then fail.
Ble.S @2
CmpM.L (A0)+,(A1)+ ; If pt.h >= r.right then fail.
Ble.S @2
@1: AddQ.B #1,RetValue(SP)
@2: PopRts ArgSize ; Pop arguments off stack and return.
EndProc
********************************************************************************************
* FUNCTION EmptyVRect (r: VRect): BOOLEAN;
* Returns true if the given rectangle is empty.
*
* Trashes: A0,A1,D0
********************************************************************************************
EmptyVRect Func Export
StackFrame Record 0,Increment
RetAddr Ds.L 1
r Ds.L 1
ArgSize Equ *-4
RetValue Ds.W 1
EndR
With StackFrame
MoveA.L r(SP),A0 ; Address of r.topLeft in A0.
Lea 8(A0),A1 ; Address of r.botRight in A1.
CmpM.L (A0)+,(A1)+ ; Compare top to bottom.
Ble.S @1 ; Fail if top >= bottom
CmpM.L (A0)+,(A1)+ ; Compare left and right.
@1: Sle D0
Neg.B D0
Move.B D0,RetValue(SP)
PopRts ArgSize ; Pop arguments off stack and return.
EndProc
********************************************************************************************
* FUNCTION EqualVRect (r1, r2: VRect): BOOLEAN;
* Returns true if the given rectangles are equal.
*
* Trashes: A0,A1,D0
********************************************************************************************
EqualVRect Func Export
StackFrame Record 0,Increment
RetAddr Ds.L 1
r2 Ds.L 1
r1 Ds.L 1
ArgSize Equ *-4
RetValue Ds.W 1
EndR
With StackFrame
MoveA.L r1(SP),A0 ; Get address of r1.
MoveA.L r2(SP),A1 ; Get address of r2.
CmpM.L (A0)+,(A1)+ ; Compare top.
Bne.S @1
CmpM.L (A0)+,(A1)+ ; Compare left.
Bne.S @1
CmpM.L (A0)+,(A1)+ ; Compare bottom.
Bne.S @1
CmpM.L (A0)+,(A1)+ ; Compare right.
@1: Seq D0
Neg.B D0
Move.B D0,RetValue(SP)
PopRts ArgSize ; Pop arguments off stack and return.
EndProc
********************************************************************************************
* FUNCTION LengthVRect (r: VRect; vhs: VHSelect): VCoordinate;
* Returns the size of the rectangle in the given dimension.
*
* Trashes: A0,A1,D0
********************************************************************************************
LengthVRect Func Export
StackFrame Record 0,Increment
RetAddr Ds.L 1
vhs Ds.W 1
r Ds.L 1
ArgSize Equ *-4
RetValue Ds.L 1
EndR
With StackFrame
MoveA.L r(SP),A0 ; Get address of r. (Points at r.top.)
Tst.B vhs(SP) ; Are we getting vertical distance?
Beq.s @1 ; Yes, branch.
AddQ.W #4,A0 ; No, point to r.left.
@1: Move.L 8(A0),D0 ; get r.botRight[vhs].
Sub.L (A0),D0 ; D0 := r.botRight[vhs] - r.topLeft[vhs].
Move.L D0,RetValue(SP) ; Set result.
PopRts ArgSize ; Pop arguments off stack and return.
EndProc
********************************************************************************************
* PROCEDURE PinVRect (r: VRect; VAR pt: VPoint);
* Pins the given point to the given rectangle.
*
* Trashes: A0,A1,D0
********************************************************************************************
PinVRect Proc Export
StackFrame Record 0,Increment
RetAddr Ds.L 1
pt Ds.L 1
r Ds.L 1
ArgSize Equ *-4
EndR
With StackFrame
MoveA.L r(SP),A0 ; Get address of r into A0.
MoveA.L pt(SP),A1 ; Get address of pt into A1.
Move.L (A1),D0 ; D0 := pt.v.
Cmp.L (A0),D0 ; Is pt.v < r.top?
Bge.S @1 ; No, branch.
Move.L (A0),D0 ; Yes, pt.v := r.top.
@1
Cmp.L 8(A0),D0 ; Is pt.v >= r.bottom?
Blt.S @2 ; No, branch.
Move.L 8(A0),D0 ; Yes, pt.v := r.bottom.
Sub.L #1,D0 ; pt.v := r.bottom - 1;
@2
Move.L D0,(A1)+ ; pt.v := D0
Move.L (A1),D0 ; D0 := pt.h.
Cmp.L 4(A0),D0 ; Is pt.h < r.left?
Bge.S @3 ; No, branch.
Move.L 4(A0),D0 ; Yes, pt.h := r.left.
@3
Cmp.L 12(A0),D0 ; Is pt.h >= r.right?
Blt.S @4 ; No, branch.
Move.L 12(A0),D0 ; Yes, pt.h := r.right.
Sub.L #1,D0 ; pt.h := r.right - 1.
@4
Move.L D0,(A1) ; pt.h := D0.
PopRts ArgSize ; Pop arguments off stack and return.
EndProc
********************************************************************************************
* FUNCTION SectVRect (src1, src2: VRect; VAR dstRect: VRect): BOOLEAN;
* Returns true if src1 and src2 intersect. dstRect is set to the intersection
* or (0,0)/(0,0) if src1 and src2 don't intersect.
*
* Trashes: A0,A1,D0,D1
********************************************************************************************
SectVRect Func Export
Import MinA0A1,MaxA0A1,ValidateRect
StackFrame Record 0,Increment
savedA2 Ds.L 1
RetAddr Ds.L 1
dstRect Ds.L 1
src2 Ds.L 1
src1 Ds.L 1
ArgSize Equ *-8
RetValue Ds.W 1
EndR
With StackFrame
Move.L A2,-(SP) ; Save A2.
MoveA.L src1(SP),A0 ; Get address of src1.
MoveA.L src2(SP),A1 ; Get address of src2.
MoveA.L dstRect(SP),A2 ; Get address of dstRect.
bsr MaxA0A1 ; D0 gets max of src1.top and src2.top.
Move.L D0,(A2)+ ; Store it in dstRect.top.
bsr MaxA0A1 ; D0 gets max of src1.left and src2.left.
Move.L D0,(A2)+ ; Store it in dstRect.left.
bsr MinA0A1 ; D0 gets min of src1.bottom and src2.bottom.
Move.L D0,(A2)+ ; Store it in dstRect.bottom.
bsr MinA0A1 ; D0 gets min of src1.right and src2.right.
Move.L D0,(A2) ; Store it in dstRect.right.
Lea -12(A2),A0 ; Now validate dstRect.
bsr ValidateRect
Move.B D0,RetValue(SP)
MoveA.L (SP)+,A2 ; Restore A2.
PopRts ArgSize ; Pop arguments off stack and return.
EndProc
********************************************************************************************
* PROCEDURE UnionVRect (src1, src2: VRect; VAR dstRect: VRect);
* Returns in dstRect the union of src1 and src2.
*
* Trashes: A0,A1,D0,D1
********************************************************************************************
UnionVRect Proc Export
Import MinA0A1,MaxA0A1
StackFrame Record 0,Increment
savedA2 Ds.L 1
RetAddr Ds.L 1
dstRect Ds.L 1
src2 Ds.L 1
src1 Ds.L 1
ArgSize Equ *-8
EndR
With StackFrame
Move.L A2,-(SP) ; Save A2.
MoveA.L src1(SP),A0 ; Get address of src1.
MoveA.L src2(SP),A1 ; Get address of src2.
MoveA.L dstRect(SP),A2 ; Get address of dstRect.
bsr MinA0A1 ; D0 gets max of src1.top and src2.top.
Move.L D0,(A2)+ ; Store it in dstRect.top.
bsr MinA0A1 ; D0 gets max of src1.left and src2.left.
Move.L D0,(A2)+ ; Store it in dstRect.left.
bsr MaxA0A1 ; D0 gets min of src1.bottom and src2.bottom.
Move.L D0,(A2)+ ; Store it in dstRect.bottom.
bsr MaxA0A1 ; D0 gets min of src1.right and src2.right.
Move.L D0,(A2) ; Store it in dstRect.right.
MoveA.L (SP)+,A2 ; Restore A2.
PopRts ArgSize ; Pop arguments off stack and return.
EndProc
********************************************************************************************
* MaxA0A1
* Returns the maximum of (A0)+ and (A1)+ in D0.
*
* Trashes: A0,A1,D0,D1
********************************************************************************************
MaxA0A1 Proc
Move.L (A0)+,D0
Move.L (A1)+,D1
Cmp.L D0,D1
Ble.S @1
Move.L D1,D0
@1
Rts
EndProc
********************************************************************************************
* MinA0A1
* Returns the minimum of (A0)+ and (A1)+ in D0.
*
* Trashes: A0,A1,D0,D1
********************************************************************************************
MinA0A1 Proc
Move.L (A0)+,D0
Move.L (A1)+,D1
Cmp.L D0,D1
Bge.S @1
Move.L D1,D0
@1
Rts
EndProc
********************************************************************************************
* ValidateRect
* Validates the rectangle at (A0). The rect is considered valid if
* (left < right) and (top < bottom). If the rect is valid then D0 returns 1
* in the low byte, else D0 returns zero in the low byte and the rect is set
* to (0,0)/(0,0).
*
* Trashes: A0,D0,D1
********************************************************************************************
ValidateRect Proc
MoveQ #1,D0 ; Seed result to true
Move.L 8(A0),D1 ; D1 := rect.bottom.
Cmp.L (A0),D1 ; Compare top to bottom.
Ble.S @1 ; It's invalid if bottom <= top.
Move.L 12(A0),D1 ; D1 := rect.right.
Cmp.L 4(A0),D1 ; Compare left and right.
Bgt.S @2 ; If right > left, then it's valid & branch.
@1: MoveQ #0,D0
Move.L D0,(A0)+ ; It's an invalid rect. Set to zeros.
Move.L D0,(A0)+
Move.L D0,(A0)+
Move.L D0,(A0)
@2: Rts
EndProc
End
;AMEN